package drds.data_propagate.binlog_event_filter.aviater;

import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.Expression;
import drds.common.$;
import drds.data_propagate.binlog_event_filter.BinlogEventFilter;
import org.apache.commons.lang.StringUtils;

import java.util.*;

/**
 * 基于aviater进行tableName正则匹配的过滤算法
 */
public class AviaterRegexBinlogEventFilter implements BinlogEventFilter<String> {

    private static final String SPLIT = ",";
    private static final String PATTERN_SPLIT = "|";
    private static final String FILTER_EXPRESSION = "regex(pattern,target)";
    private static final RegexFunction regexFunction = new RegexFunction();
    private static final Comparator<String> COMPARATOR = new StringComparator();

    static {
        AviatorEvaluator.addFunction(regexFunction);
    }

    private final Expression expression = AviatorEvaluator.compile(FILTER_EXPRESSION, true);
    final private String pattern;
    final private boolean defaultEmptyValue;

    public AviaterRegexBinlogEventFilter(String pattern) {
        this(pattern, true);
    }

    public AviaterRegexBinlogEventFilter(String patternStringListString, boolean defaultEmptyValue) {

        List<String> buildPatternStringList = null;
        if (StringUtils.isEmpty(patternStringListString)) {
            buildPatternStringList = new ArrayList<String>();
        } else {
            String[] splits = StringUtils.split(patternStringListString, SPLIT);
            buildPatternStringList = Arrays.asList(splits);
        }
        // 对pattern按照从长到短的排序
        // 因为 foo|foot 匹配 foot 会出错，原因是 foot 匹配了 foo 之后，会返回 foo，但是 foo 的长度和 foot
        // 的长度不一样
        Collections.sort(buildPatternStringList, COMPARATOR);
        // 对pattern进行头尾完全匹配
        buildPatternStringList = buildPatternStringList(buildPatternStringList);
        this.pattern = StringUtils.join(buildPatternStringList, PATTERN_SPLIT);
        //
        this.defaultEmptyValue = defaultEmptyValue;
    }

    public boolean filter(String filtered) {
        if ($.isNullOrEmpty(pattern)) {
            return defaultEmptyValue;
        }
        if ($.isNullOrEmpty(filtered)) {
            throw new IllegalArgumentException("target必须含有业务意义");
        }
        //
        Map<String, Object> env = new HashMap<String, Object>();
        env.put("pattern", pattern);
        env.put("target", filtered.toLowerCase());
        return (Boolean) expression.execute(env);
    }

    /**
     * 修复正则表达式匹配的问题，即使按照长度递减排序，还是会出现以下问题：
     *
     * <pre>
     * foooo|f.*t 匹配 fooooot 出错，原因是 fooooot 匹配了 foooo 之后，会将 fooo 和数据进行匹配，但是 foooo 的长度和 fooooot 的长度不一样
     * </pre>
     * <p>
     * 因此此类对正则表达式进行头尾完全匹配
     *
     * @author simon
     * @version 1.0.0
     */

    private List<String> buildPatternStringList(List<String> patternStringList) {
        List<String> list = new ArrayList<String>();
        for (String patternString : patternStringList) {
            StringBuilder sb = new StringBuilder();
            sb.append("^");
            sb.append(patternString);
            sb.append("$");
            list.add(sb.toString());
        }
        return list;
    }

    @Override
    public String toString() {
        return pattern;
    }

    /**
     * 修复正则表达式匹配的问题，因为使用了 oro 的 matches，会出现：
     *
     * <pre>
     * foo|foot 匹配 foot 出错，原因是 foot 匹配了 foo 之后，会返回 foo，但是 foo 的长度和 foot 的长度不一样
     * </pre>
     * <p>
     * 因此此类对正则表达式进行了从长到短的排序
     */
    private static class StringComparator implements Comparator<String> {

        public int compare(String string1, String string2) {
            if (string1.length() > string2.length()) {
                return -1;
            } else if (string1.length() < string2.length()) {
                return 1;
            } else {
                return 0;
            }
        }
    }

}
